//******************************************************************
//******************************************************************
//**********          ANts Peer To Peer Sources        *************
//
// ANts P2P realizes a third generation P2P net. It protects your
// privacy while you are connected and makes you not trackable, hiding
// your identity (ip) and crypting everything you are sending/receiving
// from others.

// Copyright (C) 2004  Roberto Rossi

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

package ants.p2p.filesharing;

import java.io.*;

import ants.p2p.*;
import ants.p2p.utils.indexer.*;

import org.apache.log4j.*;

public class InterruptedDownload {
  String fileName;
  String fileHash;
  String ed2kFileHash;
  Object[] chunkHashes;
  String extendedInfos;
  long assignedCoprime;
  long byteDownloaded;
  long fileSize;
  int blockSize;
  boolean[] downloadedBlockGroups;

  AutoresumeEngine ae;

  static Logger _logger = Logger.getLogger(InterruptedDownload.class.getName());

  public InterruptedDownload(MultipleSourcesDownloadManager store) {
    this.fileName = store.getFileName();
    this.fileHash = store.getFileHash();
    this.ed2kFileHash = store.getED2KFileHash();
    this.chunkHashes = store.chunkHashes;
    this.byteDownloaded = store.getByteDownloaded();
    this.fileSize = store.getFileSize();
    this.blockSize = store.getBlockSize();
    this.extendedInfos = store.getExtendedInfos();
    this.assignedCoprime = store.assignedCoprime;
    downloadedBlockGroups = store.getDownloadedBlockGroups();
    if(this.chunkHashes != null)
      BackgroundEngine.getInstance().addPartialFile(this);
  }

  public boolean[] getDownloadedBlockGroups(){
    return this.downloadedBlockGroups;
  }

  public InterruptedDownload(File store) throws Exception{
    ObjectInputStream ois = null;
    try{
      this.fileName = store.getName();
      if (store.exists()) {
        ois = new ObjectInputStream(new FileInputStream(store));
        this.downloadedBlockGroups = (boolean[]) ois.readObject();
        this.fileName = (String) ois.readObject();
        this.fileHash = (String) ois.readObject();
        this.ed2kFileHash = (String) ois.readObject();
        this.chunkHashes = (Object[]) ois.readObject();
        this.byteDownloaded = ( (Long) ois.readObject()).longValue();
        this.fileSize = ( (Long) ois.readObject()).longValue();
        this.blockSize = ( (Integer) ois.readObject()).intValue();
        this.assignedCoprime = ( (Long) ois.readObject()).longValue();
        this.extendedInfos = (String) ois.readObject();
        ois.close();
        if(this.blockSize != WarriorAnt.blockSizeInDownload){
          throw new Exception("Failed loading InterruptedDownload .mul file: incompatible blocksize "+this.fileName);
        }
        BackgroundEngine.getInstance().addPartialFile(this);
      }else{
        throw new Exception("Failed loading InterruptedDownload .mul file: fiile not found "+this.fileName);
      }
    }catch(Exception e){
      ois.close();
      _logger.error("Failed loading InterruptedDownload .mul file: "+store.getName()+" chuncks preserved!",e);
      throw new Exception("Failed loading InterruptedDownload .mul file: "+store.getName()+" chuncks preserved!",e);
    }
  }

  public int getAvaiablePreviewIndexes(){
    int x = 0;
    while(this.downloadedBlockGroups[x]){
      x++;
    }
    return x;
  }

  public String getPercentage() {
    int den = this.downloadedBlockGroups.length;
    int num = 0;
    for (int x = 0; x < this.downloadedBlockGroups.length; x++)
      if (this.downloadedBlockGroups[x] == true)
        num++;
    double perc = (num * 1.0 / den) * 100;
    return (int) perc + "%";
  }

  public int getBlockSize() {
    return this.blockSize;
  }

  public String getFileHash() {
    return this.fileHash;
  }

  public String getED2KFileHash(){
    return this.ed2kFileHash;
  }

  public Object[] getChunkHashes(){
    return this.chunkHashes;
  }

  public String getFileName() {
    return this.fileName;
  }

  public String getExtendedInfos(){
    return this.extendedInfos;
  }

  public long getFileSize() {
    return this.fileSize;
  }

  public long getByteDownloaded() {
    return this.byteDownloaded;
  }

  public void removeInterrupted(){
    for (int x = 0; x < this.getDownloadedBlockGroups().length; x++) {
      if (this.getDownloadedBlockGroups()[x] == true) {
        try {
          File f = new File(WarriorAnt.chunksHome + WarriorAnt.chunksPath + this.getFileHash() +
                            "." + x);
          f.delete();
        }
        catch (Exception ex) {}
      }
    }
    try {
      File f = new File(WarriorAnt.chunksHome + WarriorAnt.chunksPath + this.getFileHash() +
                        ".mul");
      f.delete();
    }
    catch (Exception ex) {}
    BackgroundEngine.getInstance().removePartialFile(this.getFileHash());
  }

  public String toString(){
    String result = this.getPercentage();
    while (result.length() < 8)
      result += " ";
    result += " " + this.sizeToString(this.getFileSize()) + " ";
    while (result.length() < 25)
      result += " ";
    result += " " + this.getFileHash() + " ";
    result += "     ";
    result += this.getFileName();
    return result;
  }

  public String sizeToString(double dSize){
    double currentSize = dSize;
    int x = 1;
    dSize = dSize / Math.pow(2, 20);
    while (dSize > 1 && x < 5) {
      dSize = dSize / Math.pow(2, 10);
      x++;
    }
    String suffix = " bytes";
    String size = currentSize+suffix;
    if (x == 2) {
      suffix = " Mib";
      size = (new Double(currentSize * 1.0 / Math.pow(2, 20))).
          toString();
      int index = size.indexOf(".");
      if (index >= 0)
        size = size.substring(0, index + 2);
      size += suffix;
    }
    if (x == 3) {
      suffix = " Gib";
      size = (new Double(currentSize * 1.0 / Math.pow(2, 30))).
          toString();
      int index = size.indexOf(".");
      if (index >= 0)
        size = size.substring(0, index + 2);
      size += suffix;
    }
    if (x == 4) {
      suffix = " Tib";
      size = (new Double(currentSize * 1.0 / Math.pow(2, 40))).
          toString();
      int index = size.indexOf(".");
      if (index >= 0)
        size = size.substring(0, index + 2);
      size += suffix;
    }
    return size;
  }

  public void addAutoresumeEngine(AutoresumeEngine ae) {
    if (this.ae != null && !this.ae.deactivated())
      this.ae.deactivate();
    this.ae = ae;
    if (this.ae != null && !this.ae.isAlive()){
      this.ae.start();
      while(!this.ae.isAlive()){
        try {
          Thread.currentThread().sleep(1000); //.yield()
        }
        catch (InterruptedException ex) {
        }
      }
    }
  }

  public AutoresumeEngine getAutoresumeEngine(){
    return this.ae;
  }

  public void deactivateAutoresumeEngine() {
    if (this.ae != null && !this.ae.deactivated()) {
      this.ae.deactivate();
      this.ae = null;
    }
  }

  public boolean isAutoresumeActive(){
    if(this.ae != null && !this.ae.deactivated())
      return true;
    else
      return false;
  }
}
